#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
using namespace std;

class Solution {
        vector<vector<int>> gh;
        vector<int> head;
        vector<int> next;
        vector<int> to;
        vector<int> indeg;
        int ecnt = 1;

        int dfs_start(int u, vector<int> &vis, stack<int> &order)
        {
                vis[u] = 1;
                for(int e = head[u]; e; e = next[e]){
                        int v = to[e];
                        if(!vis[v]){
                                if(dfs(v, vis, order) == 0){
                                        return 0;
                                }
                        }else{
                                if(vis[v] == 1){
                                        return 0;
                                }
                        }
                }
                vis[u] = 2;
                order.push(u);
                return 1;
        }

        int dfs(int u, vector<int> &vis, stack<int> &order)
        {
                vis[u] = 1;
                for(auto v : gh[u]){
                        if(!vis[v]){
                                if(dfs(v, vis, order) == 0){
                                        return 0;
                                }
                        }else{
                                if(vis[v] == 1){
                                        return 0;
                                }
                        }
                }
                vis[u] = 2;
                order.push(u);
                return 1;
        }

        vector<int> dfs_order(int v_cnt)
        {
                vector<int> vis(v_cnt, 0);
                stack<int> order;
                for(int u = 0; u < v_cnt; u++){
                        if(!vis[u]){
                                dfs_start(u, vis, order);
                        }
                }

                if(order.size() != v_cnt){
                        return {};
                }

                vector<int> ans;
                while(!order.empty()){
                        ans.push_back(order.top());
                        order.pop();
                }

                return ans;
        }

        vector<int> zero_indegree_order()
        {
                int numCourses = gh.size();
                queue<int> q;
                for(int u = 0; u < numCourses; u++){
                        if(indeg[u] == 0){
                                q.push(u);
                        }
                }

                vector<int> ans;
                while(!q.empty()){
                        int u = q.front();
                        q.pop();
                        ans.push_back(u);

                        for(int e = head[u]; e; e = next[e]){
                                int v = to[e];
                                if(--indeg[v] == 0){
                                        q.push(v);
                                }
                        }
                }

                if(ans.size() == numCourses){
                        return ans;
                }

                return {};
        }

        vector<int> zero_indegree_order(int numCourses)
        {
                queue<int> q;
                for(int u = 0; u < numCourses; u++){
                        if(indeg[u] == 0){
                                q.push(u);
                        }
                }

                vector<int> ans;
                while(!q.empty()){
                        int u = q.front();
                        q.pop();
                        ans.push_back(u);
                        for(auto v : gh[u]){
                                if(--indeg[v] == 0){
                                        q.push(v);
                                }
                        }
                }

                if(ans.size() == numCourses){
                        return ans;
                }

                return {};
        }
    public:
	vector<int> findOrder(int numCourses, vector<vector<int>> &prerequisites)
	{
                int e_cnt = prerequisites.size();
                head.resize(numCourses, 0);
                next.resize(e_cnt + 1, 0);
                to.resize(e_cnt + 1, 0);
                indeg.resize(numCourses, 0);
                gh.resize(numCourses);
                for(auto req : prerequisites){
                        int u = req[1], v = req[0];
                        gh[u].push_back(v);

                        next[ecnt] = head[u];
                        to[ecnt] = v;
                        head[u] = ecnt++;
                        indeg[v]++;
                }
                return dfs_order(numCourses);
	}
};

int main()
{
        int numCourses = 4;
        vector<vector<int>> prerequisites = {{1,0},{2,0},{3,1},{3,2}};
        vector<int> order = Solution().findOrder(numCourses, prerequisites);
        for(auto v : order){
                cout<<v<<" ";
        }
        cout<<endl;
        return 0;
}